#ifndef FUNCTIONS_H
#define FUNCTIONS_H

#include "structs.h"
#include <cstring>
#include <string>
#include <cstdio>

int proximo_final(const char* string){
  //encontra o proximo parentese de fechamento
  char ch = string[0];
  int ret = 0;
  while(ch != '\0'){
    if (ch == ')')
      return ret;
    ret++;
    ch = string[ret];
  }
  return -1;
}

float calcula_expressao(PilhaOp op,PilhaNum num){
  //calcula valor final da expressao
  float ret = remove_num(&num);
  char op_atual;
  while(op.tamanho != 0 && num.tamanho != 0){
    op_atual = remove_op(&op)[0];
    switch(op_atual){
      case '+':{
        float l_operand = remove_num(&num);
        ret = ret+l_operand;
        break;
      }
      case '-':{
      float l_operand = remove_num(&num);
      ret = ret-l_operand;
        break;
      }
      case '*':{
      float l_operand = remove_num(&num);
      ret = ret*l_operand;
        break;
      }
      case '/':{
      float l_operand = remove_num(&num);
      ret = ret/l_operand;
        break;
      }
      case '%':{
      float l_operand = remove_num(&num);
      ret = ret/l_operand;
        break;
      }
    }
  }
  return ret;
}

bool eh_operador(char op){
  //verifica se o char eh ou nao um operador reconhecido
  if(op == '+' || op == '-' ||
     op == '*' || op == '/' ||
     op == '%')
    return true;
  else
    return false;
}

float empilha_valores(const char* expressao){
  //empilha expressao ja sem os parenteses
  char atual = expressao[0];
  int i = 0;
  PilhaOp operadores = cria_pilha_vazia_op();
  PilhaNum numeros = cria_pilha_vazia_num();
  while(atual != '\0'){
    if(eh_operador(atual)){
      empilha_op(&operadores,atual);
      i++;
      atual = expressao[i];
    }
    else{
      std::string num = "";
      do{
        num += atual;
        i++;
        atual = expressao[i];
      }while(!(eh_operador(atual)) && atual != '\0');
      empilha_num(&numeros,atof(num.c_str()));
    }
  }
  return calcula_expressao(operadores,numeros);
}

using namespace std;

char* resolve_expressao(const char* expressao){
  //remove parenteses e resolve expressao
  string expressao_final;
  int index = 0;
  char atual = expressao[index];
  while(true){
    if(atual == '('){
      index++;
      const char* substring = &expressao[index];
      index += proximo_final(substring)+1;
      expressao_final.append(resolve_expressao(substring));
    }
    else if(atual == ')' || atual == '\0'){
      //fim da expressao
      char *ret = (char*) malloc(sizeof(char[5]));
      sprintf(ret,"%f",empilha_valores(expressao_final.c_str()));
      return ret;
    }
    else{
      expressao_final += atual;
      index++;
    }
    atual = expressao[index];
  }
  return NULL;
}

void output(string expressao){
  //imprime resultado da expressao
  cout << endl << endl;
  cout << expressao << " = " << resolve_expressao(expressao.c_str()) << endl;
}

std::string input(){
  //pega expressao digitada pelo usuario
  cout << "Digite uma expressao algebrica: [Ex.: (5+3)*2-(10/8)+13 ]" << endl;
  cout << "Atencao: a expressao e interpretada da direita para a esquerda." << endl;
  cout << "_>";
  string ret;
  cin >> ret;
  return ret;
}

std::string input_2(){
  //pega expressao digitada pelo usuario
  cout << "Digite uma expressao algebrica: [Ex.: (5+3)*2+13 seria escrito na forma:]"<< endl
       <<"(\n5\n+\n3\n)\n*\n2\n+\n13\n" << endl;
  cout << "Digite 'F' ou 'f' para finalizar a entrada da expressao." << endl;
  cout << "Atencao: a expressao e interpretada da direita para a esquerda." << endl;
  cout << "_>";
  string ret;
  char atual = 0;
  while(atual != 'F' && atual != 'f'){
    cin >> atual;
    if(atual !='F' && atual !='f')
      ret += atual;
  }
  return ret;
}

#endif // FUNCTIONS_H
